interface Action<T = any> {
  type: T
}
interface AnyAction extends Action {
  // Allows any extra properties to be defined in an action.
  [extraProps: string]: any
}

type Reducer<S = any, A extends Action = AnyAction> = (
  state: S | undefined,
  action: A
) => S

type Observer<T> = {
  next?(value: T): void
}

export default function createsStore<S>(reducer: Reducer, preloadedState?: S) {
  let currentListeners: Function[] = []
  let nextListeners = currentListeners
  let isDispatching = false
  let state = reducer
  let currentState = preloadedState

  function ensureCanMutateNextListeners() { }




  /**
    *添加更改侦听器。它将在任何时候被调用，
    *状态树的某些部分可能已经发生了变化。那么你可以
    *call`getState（）`读取回调中的当前状态树。
    *
    *可以从更改侦听器调用“dispatch（）”，方法如下
    *注意事项：
    *
    *一。订阅是在每次“dispatch（）”调用之前快照的。
    *如果在调用侦听器时订阅或取消订阅，则
    *不会对当前正在进行的“dispatch（）”产生任何影响。
    *但是，下一个“dispatch（）”调用（无论是否嵌套）将使用
    *订阅列表的最近快照。
    *
    *2。监听器不应该期望看到所有的状态更改，因为
    *可能在嵌套的“dispatch（）”期间多次更新
    *将调用侦听器。但是，它保证所有的订户
    *在“dispatch（）”启动之前注册的
    *在它退出时声明。
    * @param listener A callback to be invoked on every dispatch.
    * @returns A function to remove this change listener.
    */
  function subscribe(listener: Function) {
    let isSubscribed = true
    ensureCanMutateNextListeners()
    nextListeners.push(listener)
    return function unsubscribe() {
      if (!isSubscribed) {
        return
      }
      isSubscribed = false
      ensureCanMutateNextListeners()
      const index = nextListeners.indexOf(listener)
      nextListeners.splice(index, 1)
      currentListeners = null
    }
  }

  function getState() {
    return currentState as S
  }

  /**
    *分派动作。这是触发状态更改的唯一方法。
    *
    *用于创建存储的“reducer”函数将使用
    *当前状态树和给定的“操作”。其回报价值将
    *被视为树的**下一个**状态，以及更改侦听器
    *将被通知。
    *
    *基本实现只支持纯对象操作。如果你想的话
    *发出一个承诺，一个可观察到的，一个重击，或者别的什么，你需要
    *将商店创建功能包装到相应的中间件中。为了
    *例如，请参阅“redux thunk”包的文档。甚至
    *中间件最终将使用此方法分派纯对象操作。
    *
    * @param action 一个普通的对象，表示“发生了什么变化”。 它是
    * 保持操作可序列化的好主意，以便您可以记录和重放用户
    * 会话，或使用时间旅行`redux-devtools`。 一个动作必须有
    *
    * @returns For convenience, the same action object you dispatched.
    *
    * Note that, if you use a custom middleware, it may wrap `dispatch()` to
    * return something else (for example, a Promise you can await).
    */
  function dispatch(action: Action) {
    try {
      isDispatching = true
      currentState = state(currentState, action)
    } finally {
      isDispatching = false
    }
    const listeners = (currentListeners = nextListeners)
    for (let i = 0; i < listeners.length; i++) {
      const listener = listeners[i]
      listener()
    }
    return action
  }


  /**
  * 替换商店当前用于计算状态的减速器。
  *
  * 如果您的应用程序实现代码拆分并且您想要
  * 动态加载一些减速器。 如果您可能还需要此
  * 为Redux实现热重载机制。
  *
  * @param nextReducer The reducer for the store to use instead.
  * @returns The same store instance with a new reducer in place.
  */
  function replaceReducer(nextReducer: Reducer) {

  }

  function observable() {
    const outerSubscribe = subscribe
    return {
      subscribe(observer: unknown) {
        function observeState() {
          const observerAsObserver = observer as Observer<S>
          if (observerAsObserver.next) {
            observerAsObserver.next(getState())
          }
        }
        observeState()
        const unsubscribe = outerSubscribe(observeState)
        return { unsubscribe }
      }
    }
  }
  dispatch({ type: 'string' })
  const store = {
    dispatch,
    subscribe,
    getState,
    replaceReducer,
    observable
  }
  return store
}